#include "../include/KeyRecommander.h"
#include "../include/Dictionary.h"
#include "../include/Configuration.h"

#include <algorithm>

Dictionary *Dictionary::_instance = nullptr; // 懒汉模式

typename Dictionary::AutoRelease Dictionary::_ar;

std::set<int> mergeSets(const std::set<int> &set1, const std::set<int> &set2)
{
    std::set<int> mergedSet;

    // 将set1中的元素添加到合并后的集合中
    for (int num : set1)
    {
        mergedSet.insert(num);
    }

    // 将set2中的元素添加到合并后的集合中
    for (int num : set2)
    {
        mergedSet.insert(num);
    }

    return mergedSet;
}

std::vector<std::string> splitString(const std::string &input)
{
    std::vector<std::string> result;
    std::string word;
    bool isChinese = false;

    for (char c : input)
    {
        if ((c & 0x80) != 0) // 如果是中文字符
        {
            if (!isChinese)//第一次进来
            {
                if (!word.empty())
                {
                    result.push_back(word);
                    word.clear();
                }
                isChinese = true;
            }
            word += c;
        }
        else // 英文字符或空格
        {
            if (isChinese)
            {
                if (!word.empty())
                {
                    result.push_back(word);
                    word.clear();
                }
                isChinese = false;
            }
            if (!std::isspace(c))
            {
                word += c;
            }
            else if (!word.empty()) // 遇到空格
            {
                result.push_back(word);
                word.clear();
            }
        }
    }

    if (!word.empty())
    {
        result.push_back(word);
    }

    return result;
}

bool isChinese(const std::string &str)
{
    for (char c : str)
    {
        if ((c & 0x80) != 0) // 判断是否是中文字符
        {
            return true;
        }
    }
    return false;
}

void KeyRecommander::mergeVectors(const std::vector<std::vector<std::string>> &vectors)
{

    LogInfo("开始合并结果集");
    size_t maxSubVectorSize = 0;

    // 找到最大子向量的大小
    for (const auto &vec : vectors)
    {
        if (vec.size() > maxSubVectorSize)
        {
            maxSubVectorSize = vec.size();
        }
    }

    // 按照索引合并子向量的元素
    for (size_t i = 0; i < maxSubVectorSize; ++i)
    {
        std::string mergedStr;
        for (const auto &vec : vectors)
        {
            if (i < vec.size())
            {
                mergedStr += vec[i] + " ";
            }
        }
        if (!mergedStr.empty())
            mergedStr.pop_back(); // 移除最后一个空格字符
        _mergedVector.push_back(mergedStr);
    }
}

KeyRecommander::KeyRecommander(const std::string &query)
{
    // 构造函数的初始化
    _queryWords = splitString(query);

    LogInfo("KeyRecommander初始化完成;  _queryWords大小为: %d", _queryWords.size());
    int n = _queryWords.size();
    int i = _queryWords.size();

    std::cout<<"即将输出splitString(query);中英混合分割后的字符串"<<std::endl;
    while (n > 0)
    {
        cout << _queryWords[i - n] << endl;
        n--;
    }
}

std::vector<std::string> KeyRecommander::execute()
{
    // 执行查询的逻辑

    LogInfo("KeyRecommander开始执行查询");
    Dictionary *pdic = Dictionary::getInstance();

    std::vector<std::vector<std::string>> res;

    // 中英文都可以么？不考虑中英文混合，每个token 是一个 字或者字母： abc你好-----》abc 你好
    for (auto &token : _queryWords)
    {
        // 清空set
        _AssociatedWords.clear();

        //这里把abc 你好----》a b c  或者 你 好 ---》得到并集行数
        queryIndexTable(token);

        //_AssociatedWords取完：a b c 你 好 ；出现行数的并集
        LogInfo("索引表查询完成， 获取的行号个数为： %d", _AssociatedWords.size());


        // _resultQue
        std::priority_queue<MyResult, std::vector<MyResult>, MyCompare> _resultQue;

        //AsWord是 每一行行
        for (auto &AsWord : _AssociatedWords)
        {
            MyResult tmp;

            // struct MyResult {
            //     std::string _word;
            //     int _freq;
            //     int _dist;
            // };

            std::pair<std::string, int> dicr;
            if (isChinese(token))
            {
                //AsWord是行数，是从0开始还是从1开始？
                //dicr pair<词语，频次> 返回第AsWord行的 pair<词语，频次>
                dicr = pdic->FindChineseWord(AsWord);

                tmp._word = dicr.first; //词语
                tmp._freq = dicr.second;//频率

                //token：客户的关键词   dicr.first：_AssociatedWords集合中AsWord行对应的词语
                tmp._dist = distance(token, dicr.first);//距离
            }
            else
            {

                dicr = pdic->FindEnglishWord(AsWord);

                tmp._word = dicr.first;
                tmp._freq = dicr.second;

                tmp._dist = distance(token, dicr.first);
            }
            // 你好——————》你好帅 你能，
            _resultQue.push(tmp);
        }

        //关键字队列获取完成

        LogInfo("关键字队列获取完成， 大小为：  %d", _resultQue.size());

        // 现在得到了一个token词的关键字队列，从其中取出5个
        std::vector<std::string> recommandwords;
        for (int i = 0; i < 5; i++)
        {
            recommandwords.push_back(_resultQue.top()._word);
            if (_resultQue.empty())
                break;
            _resultQue.pop();
        }
        // 你好 推荐5个放 vector<std::string> recommandwords中
        //std::vector<std::vector<std::string>> res;放每个token的recommandwords
        res.push_back(recommandwords);
    }

    //所有token查询完成
    
    //std::vector<std::vector<std::string>> res;
    LogInfo("准备合并结果集");
    mergeVectors(res);

    LogInfo("结果集合并完成");
    return _mergedVector;
}

void KeyRecommander::queryIndexTable(std::string word)
{
    // 查询索引表的逻辑

    LogInfo("开始查询索引表，查询的单词为： %s", word.c_str());
    Dictionary *pdic = Dictionary::getInstance();

    if (isChinese(word))
    {
        //执行中文查询
        LogInfo("执行中文查询");
        std::set<int> newset;

        std::string result; // 存储中文字符的字符串

        // 遍历中文字符串
        for (size_t i = 0; i < word.length();)
        {
            // 获取当前字符
            char ch = word[i];

            // 判断是否为中文字符
            if ((ch & 0x80) == 0x00)
            {
                // 单字节字符
                result += ch;
                ++i;
            }
            else if ((ch & 0xE0) == 0xC0)
            {
                // 双字节字符
                result += ch;
                result += word[i + 1];
                i += 2;
            }
            else if ((ch & 0xF0) == 0xE0)
            {
                // 三字节字符
                result += ch;
                result += word[i + 1];
                result += word[i + 2];
                i += 3;
            }
            else
            {
                // 其他情况，暂不处理
                result += ch;
                ++i;
            }
            //把查询到的行数装到set newset中
            newset = pdic->FindChineseLines(result);

            //取并集
            _AssociatedWords = mergeSets(_AssociatedWords, newset);
            result.clear();
        }
    }

    // 执行英文查询
    else
    {

        LogInfo("执行英文查询");
        for (auto &c : word)
        {
            std::set<int> newset;
            std::string q;
            q += c;
            newset = pdic->FindEnglishLines(q);
            //取并集
            _AssociatedWords = mergeSets(_AssociatedWords, newset);
        }
    }
}

int KeyRecommander::distance(const std::string &lhs, const std::string &rhs)
{ // 计算最小编辑距离-包括处理中英文
    size_t lhs_len = length(lhs);
    size_t rhs_len = length(rhs);
    int editDist[lhs_len + 1][rhs_len + 1];
    for (size_t idx = 0; idx <= lhs_len; ++idx)
    {
        editDist[idx][0] = idx;
    }

    for (size_t idx = 0; idx <= rhs_len; ++idx)
    {
        editDist[0][idx] = idx;
    }

    std::string sublhs, subrhs;
    for (std::size_t dist_i = 1, lhs_idx = 0; dist_i <= lhs_len; ++dist_i, ++lhs_idx)
    {
        size_t nBytes = nBytesCode(lhs[lhs_idx]);
        sublhs = lhs.substr(lhs_idx, nBytes);
        lhs_idx += (nBytes - 1);

        for (std::size_t dist_j = 1, rhs_idx = 0; dist_j <= rhs_len; ++dist_j, ++rhs_idx)
        {
            nBytes = nBytesCode(rhs[rhs_idx]);
            subrhs = rhs.substr(rhs_idx, nBytes);
            rhs_idx += (nBytes - 1);
            if (sublhs == subrhs)
            {
                editDist[dist_i][dist_j] = editDist[dist_i - 1][dist_j - 1];
            }
            else
            {
                editDist[dist_i][dist_j] = triple_min(
                    editDist[dist_i][dist_j - 1] + 1,
                    editDist[dist_i - 1][dist_j] + 1,
                    editDist[dist_i - 1][dist_j - 1] + 1);
            }
        }
    }
    return editDist[lhs_len][rhs_len];
}

size_t KeyRecommander::nBytesCode(const char ch)
{
    if (ch & (1 << 7))
    {
        int nBytes = 1;
        for (int idx = 0; idx != 6; ++idx)
        {
            if (ch & (1 << (6 - idx)))
            {
                ++nBytes;
            }
            else
                break;
        }
        return nBytes;
    }
    return 1;
}

std::size_t KeyRecommander::length(const std::string &str)
{
    std::size_t ilen = 0;
    for (std::size_t idx = 0; idx != str.size(); ++idx)
    {
        int nBytes = nBytesCode(str[idx]);
        idx += (nBytes - 1);
        ++ilen;
    }
    return ilen;
}

int KeyRecommander::triple_min(const int &a, const int &b, const int &c)
{
    return a < b ? (a < c ? a : c) : (b < c ? b : c);
}